home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / net_ipx.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  19KB  |  707 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // net_ipx.c
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <dpmi.h>
  25.  
  26. #include "quakedef.h"
  27. #include "dosisms.h"
  28. #include "net_ipx.h"
  29.  
  30. #define    EIO                 5    /* I/O error */
  31.  
  32. #define AF_NETWARE         64
  33.  
  34. #define IPX_OPEN                    0
  35. #define IPX_CLOSE                    1
  36. #define IPX_GETROUTE                2
  37. #define IPX_SEND                    3
  38. #define IPX_LISTEN                    4
  39. #define IPX_SCHEDULEEVENT            5
  40. #define IPX_CANCEL                    6
  41. #define IPX_SCHEDULESPECIALEVENT    7
  42. #define IPX_GETINTERVALMARKER        8
  43. #define IPX_GETADDRESS                9
  44. #define IPX_RELINQUISH                10
  45.  
  46. #define PTYPE_UNKNOWN                0
  47. #define PTYPE_RIP                    1
  48. #define PTYPE_ECHO                    2
  49. #define PTYPE_ERROR                    3
  50. #define PTYPE_IPX                    4
  51. #define PTYPE_SPX                    5
  52.  
  53. #pragma pack(1)
  54.  
  55. typedef struct
  56. {
  57.     byte    network[4];
  58.     byte    node[6];
  59.     short    socket;
  60. } IPXaddr;
  61.  
  62. struct sockaddr_ipx
  63. {
  64.     short            sipx_family;
  65.     IPXaddr            sipx_addr;
  66.     char            sipx_zero[2];
  67. };
  68. #define sipx_port sipx_addr.socket
  69.  
  70. typedef struct
  71. {
  72.     short            checkSum;
  73.     short            length;
  74.     byte            transportControl;
  75.     byte            type;
  76.     IPXaddr            destination;
  77.     IPXaddr            source;
  78. } IPXheader;
  79.  
  80. typedef struct ECBStructure
  81. {
  82.     struct ECBStructure *link;
  83.     unsigned short    ESR_off;
  84.     unsigned short    ESR_seg;
  85.     byte    inUse;
  86.     byte    completionCode;
  87.     short    socket;
  88.     byte    IPXWorkspace[4];
  89.     byte    driverWorkspace[12];
  90.     byte    immediateAddress[6];
  91.     short    fragCount;
  92.     short    fragOff;
  93.     short    fragSeg;
  94.     short    fragSize;
  95. } ECB;
  96.  
  97. #pragma pack()
  98.  
  99. typedef struct
  100. {
  101.     ECB            ecb;
  102.     IPXheader    header;
  103.     int            sequence;
  104.     char        data[NET_DATAGRAMSIZE];
  105. } ipx_lowmem_buffer_t;
  106.  
  107. #define LOWMEMSIZE        (100 * 1024)
  108. #define LOWMEMSAVE        256
  109. #define IPXBUFFERS        ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t))
  110. #define IPXSOCKBUFFERS    5
  111. #define IPXSOCKETS        (IPXBUFFERS / IPXSOCKBUFFERS)
  112.  
  113. // each socket's socketbuffer 0 is used for sending, the others for listening
  114.  
  115. typedef struct
  116. {
  117.     char                reserved[LOWMEMSAVE];
  118.     ipx_lowmem_buffer_t    socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS];
  119. } ipx_lowmem_area_t;
  120.  
  121.  
  122. static int ipxsocket[IPXSOCKETS];
  123. static ECB *readlist[IPXSOCKETS];
  124. static int sequence[IPXSOCKETS];
  125. static int handlesInUse;
  126. static ipx_lowmem_area_t *lma;
  127. static char *lowmem_buffer;
  128. static int lowmem_bufseg;
  129. static int lowmem_bufoff;
  130. static unsigned short ipx_cs;
  131. static unsigned short ipx_ip;
  132. static int net_acceptsocket = -1;
  133. static int net_controlsocket;
  134.  
  135. static void IPX_PollProcedure(void);
  136. static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure};
  137.  
  138. //=============================================================================
  139.  
  140. static void IPX_GetLocalAddress(IPXaddr *addr)
  141. {
  142.     regs.x.cs = ipx_cs;
  143.     regs.x.ip = ipx_ip;
  144.     regs.x.bx = IPX_GETADDRESS;
  145.     regs.x.es = lowmem_bufseg;
  146.     regs.x.si = lowmem_bufoff;
  147.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  148.     Q_memcpy(addr, lowmem_buffer, 10);
  149. }
  150.  
  151. //=============================================================================
  152.  
  153. static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget)
  154. {
  155.     regs.x.cs = ipx_cs;
  156.     regs.x.ip = ipx_ip;
  157.     regs.x.bx = IPX_GETROUTE;
  158.     regs.x.es = lowmem_bufseg;
  159.     regs.x.si = lowmem_bufoff;
  160.     regs.x.di = lowmem_bufoff + sizeof(IPXaddr);
  161.     Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr));
  162.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  163.     if (regs.h.al)
  164.         return -1;
  165.     Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6);
  166.     return 0;
  167. }
  168.  
  169. //=============================================================================
  170.  
  171. static void IPX_ListenForPacket(ECB *ecb)
  172. {
  173.     regs.x.cs = ipx_cs;
  174.     regs.x.ip = ipx_ip;
  175.     regs.x.bx = IPX_LISTEN;
  176.     regs.x.es = ptr2real(ecb) >> 4;
  177.     regs.x.si = ptr2real(ecb) & 0xf;
  178.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  179. }
  180.  
  181. //=============================================================================
  182.  
  183. static void IPX_RelinquishControl(void)
  184. {
  185.     regs.x.cs = ipx_cs;
  186.     regs.x.ip = ipx_ip;
  187.     regs.x.bx = IPX_RELINQUISH;
  188.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  189. }
  190.  
  191.  
  192. void IPX_PollProcedure(void)
  193. {
  194.     IPX_RelinquishControl();
  195.     SchedulePollProcedure(&pollProcedure, 0.01);
  196. }
  197.  
  198. //=============================================================================
  199.  
  200. static void ProcessReadyList(int s)
  201. {
  202.     int n;
  203.     ECB *ecb;
  204.     ECB *prev;
  205.  
  206.     for (n = 1; n < IPXSOCKBUFFERS; n++)
  207.     {
  208.         if (lma->socketbuffer[s][n].ecb.inUse == 0)
  209.         {
  210.             for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link)
  211.             {
  212.                 if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence)
  213.                     break;
  214.                 prev = ecb;
  215.             }
  216.             if (ecb)
  217.                 lma->socketbuffer[s][n].ecb.link = ecb;
  218.             else
  219.                 lma->socketbuffer[s][n].ecb.link = NULL;
  220.             if (prev)
  221.                 prev->link = &lma->socketbuffer[s][n].ecb;
  222.             else
  223.                 readlist[s] = &lma->socketbuffer[s][n].ecb;
  224.             lma->socketbuffer[s][n].ecb.inUse = 0xff;
  225.         }
  226.     }
  227. }
  228.  
  229. //=============================================================================
  230.  
  231. int IPX_Init(void)
  232. {
  233.     int s;
  234.     int n;
  235.     struct qsockaddr addr;
  236.     char *colon;
  237.  
  238.     if (COM_CheckParm ("-noipx"))
  239.         return -1;
  240.  
  241.     // find the IPX far call entry point
  242.     regs.x.ax = 0x7a00;
  243.     __dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s);
  244.     if (regs.h.al != 0xff)
  245.     {
  246.         Con_Printf("IPX not detected\n");
  247.         return -1;
  248.     }
  249.     ipx_cs = regs.x.es;
  250.     ipx_ip = regs.x.di;
  251.  
  252.     // grab a chunk of memory down in DOS land
  253.     lowmem_buffer = dos_getmemory(LOWMEMSIZE);
  254.     if (!lowmem_buffer)
  255.     {
  256.         Con_Printf("IPX_Init: Not enough low memory\n");
  257.         return -1;
  258.     }
  259.     lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf;
  260.     lowmem_bufseg = ptr2real(lowmem_buffer) >> 4;
  261.  
  262.     // init socket handles & buffers
  263.     handlesInUse = 0;
  264.     lma = (ipx_lowmem_area_t *)lowmem_buffer;
  265.     for (s = 0; s < IPXSOCKETS; s++)
  266.     {
  267.         ipxsocket[s] = 0;
  268.         for (n = 0; n < IPXSOCKBUFFERS; n++)
  269.         {
  270.             lma->socketbuffer[s][n].ecb.link = NULL;
  271.             lma->socketbuffer[s][n].ecb.ESR_off = 0;
  272.             lma->socketbuffer[s][n].ecb.ESR_seg = 0;
  273.             lma->socketbuffer[s][n].ecb.socket = 0;
  274.             lma->socketbuffer[s][n].ecb.inUse = 0xff;
  275.             lma->socketbuffer[s][n].ecb.completionCode = 0;
  276.             lma->socketbuffer[s][n].ecb.fragCount = 1;
  277.             lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf;
  278.             lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4;
  279.             lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
  280.         }
  281.     }
  282.  
  283.     if ((net_controlsocket = IPX_OpenSocket (0)) == -1)
  284.     {
  285.         dos_freememory(lowmem_buffer);
  286.         Con_DPrintf ("IPX_Init: Unable to open control socket\n");
  287.         return -1;
  288.     }
  289.  
  290.     SchedulePollProcedure(&pollProcedure, 0.01);
  291.  
  292.     IPX_GetSocketAddr (net_controlsocket, &addr);
  293.     Q_strcpy(my_ipx_address,  IPX_AddrToString (&addr));
  294.     colon = Q_strrchr (my_ipx_address, ':');
  295.     if (colon)
  296.         *colon = 0;
  297.  
  298.     Con_Printf("IPX initialized\n");
  299.     ipxAvailable = true;
  300.     return net_controlsocket;
  301. }
  302.  
  303. //=============================================================================
  304.  
  305. void IPX_Shutdown(void)
  306. {
  307.     IPX_Listen (false);
  308.     IPX_CloseSocket (net_controlsocket);
  309.     dos_freememory(lowmem_buffer);
  310. }
  311.  
  312. //=============================================================================
  313.  
  314. void IPX_Listen (qboolean state)
  315. {
  316.     // enable listening
  317.     if (state)
  318.     {
  319.         if (net_acceptsocket != -1)
  320.             return;
  321.         if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1)
  322.             Sys_Error ("IPX_Listen: Unable to open accept socket\n");
  323.         return;
  324.     }
  325.  
  326.     // disable listening
  327.     if (net_acceptsocket == -1)
  328.         return;
  329.     IPX_CloseSocket (net_acceptsocket);
  330.     net_acceptsocket = -1;
  331. }
  332.  
  333. //=============================================================================
  334.  
  335. int IPX_OpenSocket(int port)
  336. {
  337.     int handle;
  338.     int n;
  339.     unsigned short socket;
  340.  
  341.     if (handlesInUse == IPXSOCKETS)
  342.         return -1;
  343.  
  344.     // open the IPX socket
  345.     regs.x.cs = ipx_cs;
  346.     regs.x.ip = ipx_ip;
  347.     regs.x.bx = IPX_OPEN;
  348.     regs.h.al = 0;
  349.     regs.x.dx = htons(port);
  350.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  351.     if (regs.h.al == 0xfe)
  352.     {
  353.         Con_DPrintf("IPX_OpenSocket: all sockets in use\n");
  354.         return -1;
  355.     }
  356.     if (regs.h.al == 0xff)
  357.     {
  358.         Con_DPrintf("IPX_OpenSocket: socket already open\n");
  359.         return -1;
  360.     }
  361.     if (regs.h.al != 0)
  362.     {
  363.         Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al);
  364.         return -1;
  365.     }
  366.     socket = regs.x.dx;
  367.  
  368. // grab a handle; fill in the ECBs, and get them listening
  369.     for (handle = 0; handle < IPXSOCKETS; handle++)
  370.     {
  371.         if (ipxsocket[handle] == 0)
  372.         {
  373.             ipxsocket[handle] = socket;
  374.             readlist[handle] = NULL;
  375.             sequence[handle] = 0;
  376.             for (n = 0; n < IPXSOCKBUFFERS; n ++)
  377.             {
  378.                 lma->socketbuffer[handle][n].ecb.socket = socket;
  379.                 lma->socketbuffer[handle][n].ecb.inUse = 0;
  380.                 if (n)
  381.                     IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb);
  382.             }
  383.             handlesInUse++;
  384.             return handle;
  385.         }
  386.     }
  387.  
  388.     // "this will NEVER happen"
  389.     Sys_Error("IPX_OpenSocket: handle allocation failed\n");
  390.     return -1;
  391. }
  392.  
  393. //=============================================================================
  394.  
  395. int IPX_CloseSocket(int handle)
  396. {
  397.     // if there's a send in progress, give it one last chance
  398.     if (lma->socketbuffer[handle][0].ecb.inUse != 0)
  399.         IPX_RelinquishControl();
  400.  
  401.     // close the socket (all pending sends/received are cancelled)
  402.     regs.x.cs = ipx_cs;
  403.     regs.x.ip = ipx_ip;
  404.     regs.x.bx = IPX_CLOSE;
  405.     regs.x.dx = ipxsocket[handle];
  406.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  407.  
  408.     ipxsocket[handle] = 0;
  409.     handlesInUse--;
  410.  
  411.     return 0;
  412. }
  413.  
  414. //=============================================================================
  415.  
  416. int IPX_Connect (int handle, struct qsockaddr *addr)
  417. {
  418.     IPXaddr ipxaddr;
  419.  
  420.     Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
  421.     if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
  422.     {
  423.         Con_Printf("Get Local Target failed\n");
  424.         return -1;
  425.     }
  426.  
  427.     return 0;
  428. }
  429.  
  430. //=============================================================================
  431.  
  432. int IPX_CheckNewConnections (void)
  433. {
  434.     int n;
  435.  
  436.     if (net_acceptsocket == -1)
  437.         return -1;
  438.  
  439.     for (n = 1; n < IPXSOCKBUFFERS; n ++)
  440.         if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0)
  441.             return net_acceptsocket;
  442.     return -1;
  443. }
  444.  
  445. //=============================================================================
  446.  
  447. int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr)
  448. {
  449.     ECB        *ecb;
  450.     ipx_lowmem_buffer_t *rcvbuf;
  451.     int        copylen;
  452.  
  453.     ProcessReadyList(handle);
  454. tryagain:
  455.     if (readlist[handle] == NULL)
  456.         return 0;
  457.     ecb = readlist[handle];
  458.     readlist[handle] = ecb->link;
  459.  
  460.     if (ecb->completionCode != 0)
  461.     {
  462.         Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode);    
  463.         ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
  464.         IPX_ListenForPacket(ecb);
  465.         goto tryagain;
  466.     }
  467.  
  468.     rcvbuf = (ipx_lowmem_buffer_t *)ecb;
  469.  
  470.     // copy the data up to the buffer
  471.     copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader));
  472.     if (len < copylen)
  473.         Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen);
  474.     Q_memcpy(buf, rcvbuf->data, copylen);
  475.  
  476.     // fill in the addr if they want it
  477.     if (addr)
  478.     {
  479.         ((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE;
  480.         Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr));
  481.         ((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0;
  482.         ((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0;
  483.     }
  484.  
  485.     // update the send ecb's immediate address
  486.     Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6);
  487.  
  488.     // get this ecb listening again
  489.     rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
  490.     IPX_ListenForPacket(&rcvbuf->ecb);
  491.     return copylen;
  492. }
  493.  
  494. //=============================================================================
  495.  
  496. int IPX_Broadcast (int handle, byte *buf, int len)
  497. {
  498.     struct sockaddr_ipx addr;
  499.     int ret;
  500.  
  501.     Q_memset(addr.sipx_addr.network, 0x00, 4);
  502.     Q_memset(addr.sipx_addr.node, 0xff, 6);
  503.     addr.sipx_port = htons(net_hostport);
  504.     Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6);
  505.     ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr);
  506.     return ret;
  507. }
  508.  
  509. //=============================================================================
  510.  
  511. int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr)
  512. {
  513.     // has the previous send completed?
  514.     while (lma->socketbuffer[handle][0].ecb.inUse != 0)
  515.         IPX_RelinquishControl();
  516.  
  517.     switch (lma->socketbuffer[handle][0].ecb.completionCode)
  518.     {
  519.         case 0x00: // success
  520.         case 0xfc: // request cancelled
  521.             break;
  522.  
  523.         case 0xfd: // malformed packet
  524.         default:
  525.             Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode);
  526.             break;
  527.  
  528.         case 0xfe: // packet undeliverable
  529.         case 0xff: // unable to send packet
  530.             Con_Printf("IPX lost route, trying to re-establish\n");
  531.  
  532.             // look for a new route
  533.             if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
  534.                 return -1;
  535.  
  536.             // re-send the one that failed
  537.             regs.x.cs = ipx_cs;
  538.             regs.x.ip = ipx_ip;
  539.             regs.x.bx = IPX_SEND;
  540.             regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
  541.             regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
  542.             __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  543.  
  544.             // report that we did not send the current one
  545.             return 0;
  546.     }
  547.  
  548.     // ecb : length
  549.     lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len;
  550.  
  551.     // ipx header : type
  552.     lma->socketbuffer[handle][0].header.type = PTYPE_IPX;
  553.  
  554.     // ipx header : destination
  555.     Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
  556.  
  557.     // sequence number
  558.     lma->socketbuffer[handle][0].sequence = sequence[handle];
  559.     sequence[handle]++;
  560.  
  561.     // copy down the data
  562.     Q_memcpy(lma->socketbuffer[handle][0].data, buf, len);
  563.  
  564.     regs.x.cs = ipx_cs;
  565.     regs.x.ip = ipx_ip;
  566.     regs.x.bx = IPX_SEND;
  567.     regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
  568.     regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
  569.     __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  570.  
  571.     return len;
  572. }
  573.  
  574. //=============================================================================
  575.  
  576. char *IPX_AddrToString (struct qsockaddr *addr)
  577. {
  578.     static char buf[28];
  579.  
  580.     sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
  581.         ((struct sockaddr_ipx *)addr)->sipx_addr.network[0],
  582.         ((struct sockaddr_ipx *)addr)->sipx_addr.network[1],
  583.         ((struct sockaddr_ipx *)addr)->sipx_addr.network[2],
  584.         ((struct sockaddr_ipx *)addr)->sipx_addr.network[3],
  585.         ((struct sockaddr_ipx *)addr)->sipx_addr.node[0],
  586.         ((struct sockaddr_ipx *)addr)->sipx_addr.node[1],
  587.         ((struct sockaddr_ipx *)addr)->sipx_addr.node[2],
  588.         ((struct sockaddr_ipx *)addr)->sipx_addr.node[3],
  589.         ((struct sockaddr_ipx *)addr)->sipx_addr.node[4],
  590.         ((struct sockaddr_ipx *)addr)->sipx_addr.node[5],
  591.         ntohs(((struct sockaddr_ipx *)addr)->sipx_port)
  592.         );
  593.     return buf;
  594. }
  595.  
  596. //=============================================================================
  597.  
  598. int IPX_StringToAddr (char *string, struct qsockaddr *addr)
  599. {
  600.     int  val;
  601.     char buf[3];
  602.  
  603.     buf[2] = 0;
  604.     Q_memset(addr, 0, sizeof(struct qsockaddr));
  605.     addr->sa_family = AF_NETWARE;
  606.  
  607. #define DO(src,dest)    \
  608.     buf[0] = string[src];    \
  609.     buf[1] = string[src + 1];    \
  610.     if (sscanf (buf, "%x", &val) != 1)    \
  611.         return -1;    \
  612.     ((struct sockaddr_ipx *)addr)->sipx_addr.dest = val
  613.  
  614.     DO(0, network[0]);
  615.     DO(2, network[1]);
  616.     DO(4, network[2]);
  617.     DO(6, network[3]);
  618.     DO(9, node[0]);
  619.     DO(11, node[1]);
  620.     DO(13, node[2]);
  621.     DO(15, node[3]);
  622.     DO(17, node[4]);
  623.     DO(19, node[5]);
  624. #undef DO
  625.  
  626.     sscanf (&string[22], "%u", &val);
  627.     ((struct sockaddr_ipx *)addr)->sipx_port = htons(val);
  628.  
  629.     return 0;
  630. }
  631.  
  632. //=============================================================================
  633.  
  634. int IPX_GetSocketAddr (int handle, struct qsockaddr *addr)
  635. {
  636.     Q_memset(addr, 0, sizeof(struct qsockaddr));
  637.     addr->sa_family = AF_NETWARE;
  638.     IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr);
  639.     ((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle];
  640.     return 0;
  641. }
  642.  
  643. //=============================================================================
  644.  
  645. int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
  646. {
  647.     Q_strcpy(name, IPX_AddrToString(addr));
  648.     return 0;
  649. }
  650.  
  651. //=============================================================================
  652.  
  653. int IPX_GetAddrFromName (char *name, struct qsockaddr *addr)
  654. {
  655.     int n;
  656.     char buf[32];
  657.  
  658.     n = Q_strlen(name);
  659.  
  660.     if (n == 12)
  661.     {
  662.         sprintf(buf, "00000000:%s:%u", name, net_hostport);
  663.         return IPX_StringToAddr (buf, addr);
  664.     }
  665.     if (n == 21)
  666.     {
  667.         sprintf(buf, "%s:%u", name, net_hostport);
  668.         return IPX_StringToAddr (buf, addr);
  669.     }
  670.     if (n > 21 && n <= 27)
  671.         return IPX_StringToAddr (name, addr);
  672.  
  673.     return -1;
  674. }
  675.  
  676. //=============================================================================
  677.  
  678. int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
  679. {
  680.     if (addr1->sa_family != addr2->sa_family)
  681.         return -1;
  682.  
  683.     if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10))
  684.         return -1;
  685.  
  686.     if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port)
  687.         return 1;
  688.  
  689.     return 0;
  690. }
  691.  
  692. //=============================================================================
  693.  
  694. int IPX_GetSocketPort (struct qsockaddr *addr)
  695. {
  696.     return ntohs(((struct sockaddr_ipx *)addr)->sipx_port);
  697. }
  698.  
  699.  
  700. int IPX_SetSocketPort (struct qsockaddr *addr, int port)
  701. {
  702.     ((struct sockaddr_ipx *)addr)->sipx_port = htons(port);
  703.     return 0;
  704. }
  705.  
  706. //=============================================================================
  707.